#include "doge-malloc.h"

#ifndef NULL
#define NULL    ((void *)0)
#endif

#define DOGE_MEM_BLOCK_SIZE    8
#define MEM_SIZE        (1024)


//__align(DOGE_MEM_BLOCK_SIZE)
static char memptr[MEM_SIZE] __attribute__ ((aligned (DOGE_MEM_BLOCK_SIZE)));    //__attribute__((at(0XC0600000)))  小端

#define MEM_ADDR_START  &memptr[0]
#define MEM_ADDR_END  &memptr[MEM_SIZE-1]

//#pragma pack(1)
struct mem_struct {
    void *ptr;
    unsigned int size;
    unsigned int block_size;
    unsigned int used[MEM_SIZE/DOGE_MEM_BLOCK_SIZE];
};
//#pragma pack()


static char init_ok = 0;       //__attribute__((at(0XC0600000)))

struct mem_struct mem_obj;

static unsigned int free_block;
static void *free_ptr = NULL;

static void doge_malloc_init(void)
{
    unsigned int index;

    if (!init_ok)
    {
        init_ok = 1;
        mem_obj.ptr = MEM_ADDR_START;
        mem_obj.block_size = DOGE_MEM_BLOCK_SIZE;
        mem_obj.size = MEM_SIZE;
        printf("MEM_ADDR_START - %p  MEM_ADDR_END - %p\r\n", MEM_ADDR_START, MEM_ADDR_END);
        for (index = 0; index < (MEM_SIZE/DOGE_MEM_BLOCK_SIZE); index++)
        {
            mem_obj.used[index] = 0;
        }
    }
}

void *doge_malloc(unsigned int size)
{
    signed long index;
    int i;
    int need_blocks;
    int not_used_blocks = 0;

    doge_malloc_init();

    if (size == 0)
        return NULL;

    /* Calculate the number of memory blocks required to apply for the memory size */
    need_blocks = size/DOGE_MEM_BLOCK_SIZE;量 */
    if (size % DOGE_MEM_BLOCK_SIZE)     
        need_blocks++;

//    printf("mallocc blocknum - %d\r\n", blocknum);

    for ( index = (MEM_SIZE/DOGE_MEM_BLOCK_SIZE)-1; index >= 0; index--)
    {
        if (mem_obj.used[index] == 0)       /* the memory block is not used */ 
        {
            not_used_num++;                 /* Count the number of contiguous unused memory blocks */ 
        }
        else
        {
            not_used_num = 0;
        }
        /* The contiguous memory blocks match the size of the requested memory 如果连续内存块符合申请大小 */ 
        if (not_used_num == need_blocks)     
        {
            for (i = 0; i < need_blocks; i++)
            {
                mem_obj.used[index+i] = need_blocks;
            }
            return (void *)(mem_obj.ptr+index*DOGE_MEM_BLOCK_SIZE);
        }

    }
    return NULL;
}


int doge_free(void *ptr)
{
    int index;
    int used_blocks;   /* count of used block */
    int offset;   /* size of memory to free */
    int i;

    if (ptr == NULL)
    {
        printf("ptr is null\r\n");
        return -1;
    }

    offset = (char *)ptr - MEM_ADDR_START;   /* Get size of free memory block*/
    printf("free addr - %p offset - %d\r\n", ptr, offset);
    if (offset > MEM_SIZE)    /* This memory is not belong to this memory pool */ 
    {
        printf("offset is out of range\r\n");
        return -2;
    }

    doge_malloc_init();

    index = offset / DOGE_MEM_BLOCK_SIZE;  /* Get index of memory blocks */
    used_blocks = mem_obj.used[index];    /* Get count of used block */  
    printf("index - %d  used_blocks - %d\r\n", index, used_blocks);

    /* Clear used flag, indicates that the memory is released */
    for (i = 0; i < used_blocks; i++)
    {
        mem_obj.used[index+i] = 0;     
    }
    free_block = used_blocks;
    free_ptr = ptr;
    ptr = NULL;
    return 0;

    printf("doge free end, free addr - %p\r\n", ptr);
}

void *doge_remalloc(void *ptr, unsigned int size)
{
    if (ptr == NULL)
        return NULL;

    if (size == 0)
        return ptr;

    doge_free(ptr);            // 先释放内存
#if 1
    char *newptr = (char *)doge_malloc(size);
    if (newptr == NULL)                   // 重新分配成功
        return NULL;

    char *free = (char *)free_ptr;
    while (size--)
            *newptr++ = free++;

    return newptr;
#else
    if (newptr == NULL)                   // 重新分配成功
        return NULL;

    if (newptr == free_ptr)
        return newptr;

    if (newptr < free_ptr || newptr > (free_ptr+free_block*DOGE_MEM_BLOCK_SIZE))
    {
        while (size--)
            *newptr++ = free_ptr++;
    }
    else              //新地址大于旧地址且地址有重叠,不进行数据拷贝
    {
        return newptr;
    }
#endif
}
